﻿using System;
using System.Net;
using System.Security;
using System.Security.Principal;

namespace TFSBugTracking
{
    /// <summary>
    /// translates a given identity into another credential set when found oin the mapping setup
    /// used to translate from the current user account into a tfs-known user account
    /// </summary>
    public class TfsCredentialTranslator
    {
        private readonly TfsImpersonationMap[] _mappings;

        /// <summary>
        /// default ctor reading the mapping info and storing the current identity for later translation
        /// </summary>
        /// <param name="currentIdentity">input identity to translate</param>
        /// <param name="mappingsPath">path to the file storing user user mapping info</param>
        public TfsCredentialTranslator(IIdentity currentIdentity, string mappingsPath)
        {
            if (currentIdentity == null) throw new ArgumentNullException("currentIdentity");
            CurrentIdentity = currentIdentity;

            _mappings = TfsImpersonationMap.GetMappings(mappingsPath);
        }

        /// <summary>
        ///Gets the current ID (passed in during construction) 
        /// </summary>
        public IIdentity CurrentIdentity { get; private set; }

        /// <summary>
        /// looks up the <see cref="CurrentIdentity"/>, searches a valid representation in the
        /// mappings and returns new credentials from the approprate mapping to be used for impersonation
        /// </summary>
        /// <returns>impersonatio credentials</returns>
        /// <exception cref="SecurityException">thrown when no matching user was found</exception>
        public NetworkCredential ToTfs2010Credential()
        {
            //loop through mappings in place
            foreach (TfsImpersonationMap tfsImpersonationMap in _mappings)
            {
                bool found = false;
                //if a * char is 1st char, only the end of the user name must match
                if (tfsImpersonationMap.SourceUserName.StartsWith("*"))
                {
                    //cut the * char
                    string searchString = tfsImpersonationMap.SourceUserName.Substring(1, tfsImpersonationMap.SourceUserName.Length - 1);
                    //match identity name with search sub string
                    found = CurrentIdentity.Name.EndsWith(searchString, StringComparison.InvariantCultureIgnoreCase);
                }
                else
                {
                    //find exact user name
                    found = CurrentIdentity.Name.Equals(tfsImpersonationMap.SourceUserName, StringComparison.InvariantCultureIgnoreCase);
                }
                //return credentials when match was found
                if (found)
                {
                    if ( tfsImpersonationMap.TargetPassword.Length > 20)
                        return new NetworkCredential(tfsImpersonationMap.TargetUserName, tfsImpersonationMap.TargetPassword.Decrypt(tfsImpersonationMap.TargetUserName));
                    else 
                        return new NetworkCredential(tfsImpersonationMap.TargetUserName, tfsImpersonationMap.TargetPassword);    
                    
                }
            }

            //throw exception when no match was found
            throw new SecurityException("unable to impersonate user: " + CurrentIdentity.Name + ". Add Account to UserMapping.xml.");
        }
    }
}